package org.lex.swing;

import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.io.File;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.UIManager;

/**
 * Operating system detection routines.
 */
public class OperatingSystem {
	private static int hasScreenMenuBar = -1;

	private static boolean java14;

	private static boolean java15;

	private static final int MAC_OS_X = 0xABC;

	private static int os;

	private static final int OS2 = 0xDEAD;

	private static final int UNIX = 0x31337;

	private static final int UNKNOWN = 0xBAD;

	private static final int VMS = 0xDEAD2;

	private static final int WINDOWS_9x = 0x640;

	private static final int WINDOWS_NT = 0x666;

	// {{{ Class initializer
	static {
		if (System.getProperty("mrj.version") != null) {
			os = MAC_OS_X;
		} else {
			String osName = System.getProperty("os.name");
			if (osName.indexOf("Windows 9") != -1 || osName.indexOf("Windows M") != -1) {
				os = WINDOWS_9x;
			} else if (osName.indexOf("Windows") != -1) {
				os = WINDOWS_NT;
			} else if (osName.indexOf("OS/2") != -1) {
				os = OS2;
			} else if (osName.indexOf("VMS") != -1) {
				os = VMS;
			} else if (File.separatorChar == '/') {
				os = UNIX;
			} else {
				os = UNKNOWN;
			}
		}

		// for debugging, make jEdit think its using a different
		// version of Java than it really is.
		String javaVersion = System.getProperty("jedit.force.java.version");
		if (javaVersion == null || javaVersion.equals(""))
			javaVersion = System.getProperty("java.version");
		java14 = (javaVersion.compareTo("1.4") >= 0);
		java15 = (javaVersion.compareTo("1.5") >= 0);
	}

	/**
	 * Returns the bounds of the default screen.
	 */
	public static final Rectangle getScreenBounds() {
		int screenX = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
		int screenY = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
		int x, y, w, h;

		if (isMacOS()) {
			x = 0;
			y = 22;
			w = screenX;
			h = screenY - y - 4;// shadow size
		} else if (isWindows()) {
			x = -4;
			y = -4;
			w = screenX - 2 * x;
			h = screenY - 2 * y;
		} else {
			x = 0;
			y = 0;
			w = screenX;
			h = screenY;
		}

		return new Rectangle(x, y, w, h);
	}

	/**
	 * Returns the bounds of the (virtual) screen that the window should be in
	 * 
	 * @param window
	 *            The bounds of the window to get the screen for
	 */
	public static final Rectangle getScreenBounds(Rectangle window) {
		GraphicsDevice[] gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
		Vector<GraphicsConfiguration> intersects = new Vector<GraphicsConfiguration>();

		// Get available screens
		// O(n^3), this is nasty, but since we aren't dealling with
		// many items it should be fine
		for (int i = 0; i < gd.length; i++) {
			GraphicsConfiguration gc = gd[i].getDefaultConfiguration();
			// Don't add duplicates
			if (window.intersects(gc.getBounds())) {
				Enumeration<GraphicsConfiguration> e = intersects.elements();
				for (; e.hasMoreElements();) {
					GraphicsConfiguration gcc = e.nextElement();
					if (gcc.getBounds().equals(gc.getBounds()))
						break;
				}
				intersects.add(gc);
			}
		}

		GraphicsConfiguration choice = null;
		if (intersects.size() > 0) {
			// Pick screen with largest intersection
			for (Enumeration<GraphicsConfiguration> e = intersects.elements(); e.hasMoreElements();) {
				GraphicsConfiguration gcc = e.nextElement();
				if (choice == null)
					choice = gcc;
				else {
					Rectangle int1 = choice.getBounds().intersection(window);
					Rectangle int2 = gcc.getBounds().intersection(window);
					int area1 = int1.width * int1.height;
					int area2 = int2.width * int2.height;
					if (area2 > area1)
						choice = gcc;
				}
			}
		} else
			choice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

		// Make adjustments for some OS's
		int screenX = (int) choice.getBounds().x;
		int screenY = (int) choice.getBounds().y;
		int screenW = (int) choice.getBounds().width;
		int screenH = (int) choice.getBounds().height;
		int x, y, w, h;

		if (isMacOS()) {
			x = screenX;
			y = screenY + 22;
			w = screenW;
			h = screenH - y - 4;// shadow size
		} else if (isWindows()) {
			x = screenX - 4;
			y = screenY - 4;
			w = screenW - 2 * x;
			h = screenH - 2 * y;
		} else {
			x = screenX;
			y = screenY;
			w = screenW;
			h = screenH;
		}

		// Yay, we're finally there
		return new Rectangle(x, y, w, h);
	}

	/**
	 * Returns if Java 2 version 1.4, or Java 2 version 1.5 is in use.
	 */
	public static final boolean hasJava14() {
		return java14;
	}

	/**
	 * Returns if Java 2 version 1.5 is in use.
	 */
	public static final boolean hasJava15() {
		return java15;
	} // }}}

	/**
	 * Returns whether the screen menu bar on Mac OS X is in use.
	 * 
	 * @since jEdit 4.2pre1
	 */
	public static final boolean hasScreenMenuBar() {
		if (!isMacOS())
			return false;
		else if (hasScreenMenuBar == -1) {
			String result = System.getProperty("apple.laf.useScreenMenuBar");
			if (result == null)
				result = System.getProperty("com.apple.macos.useScreenMenuBar");
			hasScreenMenuBar = ("true".equals(result)) ? 1 : 0;
		}

		return (hasScreenMenuBar == 1);
	}

	/**
	 * Returns if we're running Windows 95/98/ME/NT/2000/XP, or OS/2.
	 */
	public static final boolean isDOSDerived() {
		return isWindows() || isOS2();
	}

	/**
	 * Returns if we're running MacOS X.
	 */
	public static final boolean isMacOS() {
		return os == MAC_OS_X;
	}

	/**
	 * Returns if we're running MacOS X and using the native look and feel.
	 */
	public static final boolean isMacOSLF() {
		return (isMacOS() && UIManager.getLookAndFeel().isNativeLookAndFeel());
	}

	/**
	 * Returns if we're running OS/2.
	 */
	public static final boolean isOS2() {
		return os == OS2;
	}

	/**
	 * Returns if we're running Unix (this includes MacOS X).
	 */
	public static final boolean isUnix() {
		return os == UNIX || os == MAC_OS_X;
	}

	/**
	 * Returns if we're running VMS.
	 */
	public static final boolean isVMS() {
		return os == VMS;
	}

	/**
	 * Returns if we're running Windows 95/98/ME/NT/2000/XP.
	 */
	public static final boolean isWindows() {
		return os == WINDOWS_9x || os == WINDOWS_NT;
	}

	/**
	 * Returns if we're running Windows 95/98/ME.
	 */
	public static final boolean isWindows9x() {
		return os == WINDOWS_9x;
	}

	/**
	 * Returns if we're running Windows NT/2000/XP.
	 */
	public static final boolean isWindowsNT() {
		return os == WINDOWS_NT;
	}

	/**
	 * Returns if this OS is likely to be using X11 as the graphics system.
	 * 
	 * @since jEdit 4.2pre3
	 */
	public static boolean isX11() {
		return os == UNIX;
	}
}
